<template>
  <view class="fixed flex" :style="[_pos?.parent, { zIndex: 402 }]">
    <!-- 主按钮。 -->
    <view
      :style="{ width: props.width + 'rpx', height: props.height + 'rpx' }"
      class="flex flex-row flex-row-center-center"
    >
      <slot>
        <tm-button
          :follow-theme="props.followTheme"
          _class="flex flex-col flex-col-center-center"
          :shadow="3"
          :linear="_btn.linear"
          :linear-deep="_btn.linearDeep"
          :color="_btn.color"
          :margin="[0, 0]"
          :round="16"
          :padding="[0, 0]"
          :width="props.width - 24"
          @click="onclick"
          :height="props.height - 24"
          :open-type="_btn.openType"
          @getphonenumber="btnCall($event, _btn)"
          @error="btnCall($event, _btn)"
          @opensetting="btnCall($event, _btn)"
          @launchapp="btnCall($event, _btn)"
          @contact="btnCall($event, _btn)"
          @chooseavatar="btnCall($event, _btn)"
        >
          <view class="flex flex-col flex-col-center-center">
            <tm-icon
              :user-interaction-enabled="false"
              :follow-dark="false"
              :color="_btn.fontColor"
              :name="_btn.icon"
              :font-size="_btn.iconSize"
            ></tm-icon>
            <tm-text
              v-if="_btn.label"
              :user-interaction-enabled="false"
              :follow-dark="false"
              :color="_btn.fontColor"
              :label="_btn.label"
              :font-size="_btn.fontSize"
            ></tm-text>
          </view>
        </tm-button>
      </slot>
    </view>
    <!-- 子按钮。 -->
    <view
      v-if="showActions && _actionsItem.length > 0"
      class="fixed zIndex-12"
      :style="_pos?.children"
      :user-interaction-enabled="showActions"
    >
      <view
        v-for="(item, index) in _actionsItem"
        ref="btnChildren"
        :key="index"
        :style="{ width: props.width + 'rpx', height: props.height + 'rpx' }"
        :class="[showActions && _actionsItem.length > 0 ? 'scaleNvue' : '']"
        class="flex flex-row flex-row-center-center scale"
      >
        <tm-button
          :follow-theme="props.followTheme"
          _class="flex flex-col flex-col-center-center"
          :shadow="3"
          :linear="item.linear"
          :linear-deep="item.linearDeep"
          :color="item.color"
          :margin="[0, 0]"
          :round="16"
          :padding="[0, 0]"
          :width="props.width - 24"
          @click="change(index, item)"
          :height="props.height - 24"
          :open-type="item.openType"
          @getphonenumber="btnCall($event, item)"
          @error="btnCall($event, item)"
          @opensetting="btnCall($event, item)"
          @launchapp="btnCall($event, item)"
          @contact="btnCall($event, item)"
          @chooseavatar="btnCall($event, item)"
        >
          <view class="flex flex-col flex-col-center-center">
            <tm-icon
              :user-interaction-enabled="false"
              :follow-dark="false"
              :color="item.fontColor"
              :name="item.icon"
              :font-size="item.iconSize"
            ></tm-icon>
            <tm-text
              v-if="item.label"
              :user-interaction-enabled="false"
              :follow-dark="false"
              :color="item.fontColor"
              :label="item.label"
              :font-size="item.fontSize"
            ></tm-text>
          </view>
        </tm-button>
      </view>
    </view>
  </view>
</template>
<script lang="ts" setup>
/**
 * 悬浮按钮
 * @description 总共6个位置，每个位置有四方向的子按钮展开位置，一共24个位置可控制。具体看文档。
 * @example <tm-floatButton :btn="{icon:'tmicon-plus',linear:'top'}"></tm-floatButton>
 * @method click 主按钮被点击，(e:Event)
 * @method change  子按钮被点击， (index:number,item:actionsItem)
 */
import { computed, PropType, ref, inject, getCurrentInstance, onMounted } from 'vue'
import { positionType, popDir, actionsItem } from './interface'
import tmSheet from '../tm-sheet/tm-sheet.vue'
import tmIcon from '../tm-icon/tm-icon.vue'
import tmText from '../tm-text/tm-text.vue'
import tmButton from '../tm-button/tm-button.vue'
import { useWindowInfo } from '../../tool/useFun/useWindowInfo'

// #ifdef APP-PLUS-NVUE
const animation = uni.requireNativePlugin('animation')
// #endif
/**
 * 事件说明
 * click：主按钮被点击，
 * change :子按钮被点击，
 */
const emits = defineEmits(['click', 'change'])
const props = defineProps({
  followTheme: {
    type: [Boolean],
    default: true,
  },
  //主按钮的位置
  position: {
    type: String as PropType<'bc' | 'bl' | 'br' | 'tc' | 'tl' | 'tr'>,
    default: 'br',
  },
  //子菜单弹出的位置
  actionsPos: {
    type: String as PropType<'left' | 'right' | 'top' | 'bottom'>,
    default: 'top',
  },
  width: {
    type: Number,
    default: 124,
  },
  height: {
    type: Number,
    default: 124,
  },
  offset: {
    type: Array as PropType<Array<number>>,
    default: () => [32, 32],
  },
  //子按钮组数据
  actions: {
    type: Array as PropType<Array<actionsItem>>,
    default: () => [],
  },
  // 主按钮对象数据
  btn: {
    type: Object as PropType<actionsItem>,
    default: () => {},
    required: true,
  },
  //是否默认显示子菜单
  showActions: {
    type: Boolean,
    default: false,
  },
  //点击子菜单后，是否需要隐藏，如果为false,点击子按钮后不会隐藏按钮。始终保持展开子按钮。
  clickHidnActions: {
    type: Boolean,
    default: true,
  },
  disabledScrollTo: {
    type: Boolean,
    default: true,
  },
  scrollTo: {
    type: Object as PropType<{ scrollTop: number; selector: string; duration: number }>,
    default: () => {
      return {
        scrollTop: 0,
        selector: '',
        duration: 300,
      }
    },
  },
})

const sysinfo = useWindowInfo()
const windowWidth = computed(() => sysinfo.width)
const windowTop = computed(() => sysinfo.top)
const proxy = getCurrentInstance()?.proxy ?? null
const isH5 = ref(false)
// #ifdef H5
isH5.value = true
// #endif
const showActions = ref(props.showActions ?? false)
const BtnPos = computed(() => props.position)
const AcionPos = computed(() => props.actionsPos)
const _offset = computed(() => {
  let ost = props.offset ?? [0, 0]
  ost = [uni.upx2px(props.offset[0]), uni.upx2px(props.offset[1])]
  return ost
})
const centerPosLeft = computed(() => {
  let ps = (windowWidth.value - uni.upx2px(props.width * 2)) / 2 + _offset.value[0] * 2
  return ps
})

const _btn = computed(() => {
  return {
    icon: 'tmicon-plus',
    fontSize: 20,
    color: 'primary',
    linear: '',
    linearDeep: 'accent',
    label: '',
    iconSize: 42,
    fontColor: '',
    ...(props.btn ?? {}),
  }
})
const _actionsItem = computed(() => {
  let asbtn = props.actions.map((el) => {
    let default_btn: actionsItem = {
      icon: 'tmicon-plus',
      fontSize: 20,
      color: 'primary',
      linear: '',
      linearDeep: 'accent',
      label: '',
      fontColor: '',
      iconSize: 36,
    }
    return { ...default_btn, ...el }
  })
  return asbtn
})

const _pos = computed(() => {
  let gutter = uni.upx2px(24)
  let actionwidth_total = _actionsItem.value.length * uni.upx2px(props.width)
  let actionwidth = uni.upx2px(props.width)
  if (AcionPos.value == 'left' && BtnPos.value == 'bc') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        left: centerPosLeft.value + 'px',
      },
      children: {
        bottom: _offset.value[1] + 'px',
        left: centerPosLeft.value - actionwidth_total + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'right' && BtnPos.value == 'bc') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        left: centerPosLeft.value + 'px',
      },
      children: {
        bottom: _offset.value[1] + 'px',
        left: centerPosLeft.value + actionwidth + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'bottom' && BtnPos.value == 'bc') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        left: centerPosLeft.value + 'px',
      },
      children: {
        bottom: _offset.value[1] - actionwidth_total + 'px',
        left: centerPosLeft.value + 'px',
      },
    }
  }
  if (AcionPos.value == 'top' && BtnPos.value == 'bc') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        left: centerPosLeft.value + 'px',
      },
      children: {
        bottom: _offset.value[1] + actionwidth + 'px',
        left: centerPosLeft.value + 'px',
      },
    }
  }

  if (AcionPos.value == 'right' && BtnPos.value == 'bl') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        left: _offset.value[0] + 'px',
      },
      children: {
        bottom: _offset.value[1] + 'px',
        left: _offset.value[0] + actionwidth + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'left' && BtnPos.value == 'bl') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        left: _offset.value[0] + 'px',
      },
      children: {
        bottom: _offset.value[1] + 'px',
        left: _offset.value[0] - actionwidth_total + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'top' && BtnPos.value == 'bl') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        left: _offset.value[0] + 'px',
      },
      children: {
        bottom: _offset.value[1] + actionwidth + 'px',
        left: _offset.value[0] + 'px',
      },
    }
  }
  if (AcionPos.value == 'bottom' && BtnPos.value == 'bl') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        left: _offset.value[0] + 'px',
      },
      children: {
        bottom: _offset.value[1] - actionwidth_total + 'px',
        left: _offset.value[0] + 'px',
      },
    }
  }

  if (AcionPos.value == 'right' && BtnPos.value == 'br') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        right: _offset.value[0] + 'px',
      },
      children: {
        bottom: _offset.value[1] + 'px',
        right: _offset.value[0] - actionwidth_total + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'left' && BtnPos.value == 'br') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        right: _offset.value[0] + 'px',
      },
      children: {
        bottom: _offset.value[1] + 'px',
        right: _offset.value[0] + actionwidth + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'top' && BtnPos.value == 'br') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        right: _offset.value[0] + 'px',
      },
      children: {
        bottom: _offset.value[1] + actionwidth + 'px',
        right: _offset.value[0] + 'px',
      },
    }
  }
  if (AcionPos.value == 'bottom' && BtnPos.value == 'br') {
    return {
      parent: {
        bottom: _offset.value[1] + 'px',
        right: _offset.value[0] + 'px',
      },
      children: {
        bottom: _offset.value[1] - actionwidth_total + 'px',
        right: _offset.value[0] + 'px',
      },
    }
  }

  if (AcionPos.value == 'left' && BtnPos.value == 'tc') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        left: centerPosLeft.value + 'px',
      },
      children: {
        top: _offset.value[1] + 'px',
        left: centerPosLeft.value - actionwidth_total + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'right' && BtnPos.value == 'tc') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        left: centerPosLeft.value + 'px',
      },
      children: {
        top: _offset.value[1] + 'px',
        left: centerPosLeft.value + actionwidth + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'bottom' && BtnPos.value == 'tc') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        left: centerPosLeft.value + 'px',
      },
      children: {
        top: _offset.value[1] + actionwidth + 'px',
        left: centerPosLeft.value + 'px',
      },
    }
  }
  if (AcionPos.value == 'top' && BtnPos.value == 'tc') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        left: centerPosLeft.value + 'px',
      },
      children: {
        top: _offset.value[1] - actionwidth_total + 'px',
        left: centerPosLeft.value + 'px',
      },
    }
  }

  if (AcionPos.value == 'right' && BtnPos.value == 'tl') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        left: _offset.value[0] + 'px',
      },
      children: {
        top: _offset.value[1] + 'px',
        left: _offset.value[0] + actionwidth + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'left' && BtnPos.value == 'tl') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        left: _offset.value[0] + 'px',
      },
      children: {
        top: _offset.value[1] + 'px',
        left: _offset.value[0] - actionwidth_total + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'top' && BtnPos.value == 'tl') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        left: _offset.value[0] + 'px',
      },
      children: {
        top: _offset.value[1] - actionwidth_total + 'px',
        left: _offset.value[0] + 'px',
      },
    }
  }
  if (AcionPos.value == 'bottom' && BtnPos.value == 'tl') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        left: _offset.value[0] + 'px',
      },
      children: {
        top: _offset.value[1] + actionwidth + 'px',
        left: _offset.value[0] + 'px',
      },
    }
  }

  if (AcionPos.value == 'right' && BtnPos.value == 'tr') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        right: _offset.value[0] + 'px',
      },
      children: {
        top: _offset.value[1] + 'px',
        right: _offset.value[0] - actionwidth_total + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'left' && BtnPos.value == 'tr') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        right: _offset.value[0] + 'px',
      },
      children: {
        top: _offset.value[1] + 'px',
        right: _offset.value[0] + actionwidth + 'px',
        display: 'flex',
        'flex-direction': 'row',
      },
    }
  }
  if (AcionPos.value == 'top' && BtnPos.value == 'tr') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        right: _offset.value[0] + 'px',
      },
      children: {
        top: _offset.value[1] - actionwidth_total + 'px',
        right: _offset.value[0] + 'px',
      },
    }
  }
  if (AcionPos.value == 'bottom' && BtnPos.value == 'tr') {
    return {
      parent: {
        top: _offset.value[1] + 'px',
        right: _offset.value[0] + 'px',
      },
      children: {
        top: _offset.value[1] + actionwidth + 'px',
        right: _offset.value[0] + 'px',
      },
    }
  }
})

function onclick(e: any) {
  if (props.clickHidnActions) {
    showActions.value = !showActions.value
    // #ifdef APP-NVUE
    setTimeout(function () {
      nvueani()
    }, 50)
    // #endif
  } else {
    showActions.value = true
  }
  emits('click', e)
  // #ifndef APP-NVUE
  if (!props.disabledScrollTo) {
    uni.pageScrollTo({
      scrollTop: props.scrollTo.scrollTop,
      duration: props.scrollTo.duration,
      selector: props.scrollTo.selector,
    })
  }
  // #endif
}
onMounted(() => {
  if (showActions.value) {
    // #ifdef APP-NVUE
    setTimeout(function () {
      nvueani()
    }, 50)
    // #endif
  }
})
function change(index: number, item: actionsItem) {
  if (props.clickHidnActions) {
    showActions.value = false
  }
  emits('change', index, item)
}

function btnCall(event: any, item: actionsItem) {
  if (typeof item?.callback === 'function') {
    item.callback(event, item)
  }
}

function nvueani() {
  let el = proxy?.$refs?.btnChildren ?? null
  if (!el) return
  let pel = []
  if (!Array.isArray(el)) {
    pel = [el]
  } else {
    pel = [...el]
  }
  pel.forEach((element) => {
    animation.transition(
      element,
      {
        styles: {
          opacity: 1,
          transform: 'scale(1,1)',
          transformOrigin: 'center center',
        },
        duration: 340, //ms
        timingFunction: 'ease',
        delay: 0, //ms
      },
      () => {}
    )
  })
}
</script>
<style scoped>
/* #ifdef APP-NVUE */
.scaleNvue {
  opacity: 0;
  transform: scale(0);
}
/* #endif */
/* #ifndef APP-NVUE */
.scale {
  animation: scale 0.34s ease;
}
@keyframes scale {
  0% {
    transform: scale(0);
  }

  40% {
    transform: scale(1.2);
  }
  100% {
    transform: scale(1);
  }
}
/* #endif */
</style>
